home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / ntfs / common / attr.c next >
Encoding:
C/C++ Source or Header  |  2001-02-11  |  15.3 KB  |  623 lines

  1. /*
  2.  *  attr.c
  3.  *
  4.  *  Copyright (C) 1996-1999 Martin von L÷wis
  5.  *  Copyright (C) 1996-1997 RΘgis Duchesne
  6.  *  Copyright (C) 1998 Joseph Malicki
  7.  *  Copyright (C) 1999 Steve Dodd
  8.  */
  9.  
  10. #include "ntfstypes.h"
  11. #include "struct.h"
  12. #include "attr.h"
  13.  
  14. #include <errno.h>
  15. #ifdef HAVE_STRING_H
  16. #include <string.h>
  17. #endif
  18. #include "macros.h"
  19. #include "support.h"
  20. #include "util.h"
  21. #include "super.h"
  22. #include "inode.h"
  23.  
  24. /* Look if an attribute already exists in the inode, and if not, create it */
  25. int 
  26. ntfs_new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos,
  27.             int *found, int do_search )
  28. {
  29.     int do_insert=0;
  30.     int i;
  31.  
  32.     for(i=0;i<ino->attr_count;i++)
  33.     {
  34.         int n=min(namelen,ino->attrs[i].namelen);
  35.         int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n);
  36.         if( do_search ) {
  37.             /*
  38.              * We assume that each attribute can be uniquely 
  39.              * identified by inode
  40.              * number, attribute type and attribute name.
  41.              */
  42.             if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
  43.                 *found=1;
  44.                 *pos=i;
  45.                 return 0;
  46.             }
  47.         }
  48.         /* attributes are ordered by type, then by name */
  49.         if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){
  50.             do_insert=1;
  51.             break;
  52.         }
  53.     }
  54.  
  55.     /* re-allocate space */
  56.     if(ino->attr_count % 8 ==0)
  57.     {
  58.         ntfs_attribute* new;
  59.         new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
  60.                  sizeof(ntfs_attribute));
  61.         if( !new )
  62.             return ENOMEM;
  63.         if( ino->attrs ) {
  64.             ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) );
  65.             ntfs_free( ino->attrs );
  66.         }
  67.         ino->attrs = new;
  68.     }
  69.     if(do_insert)
  70.         ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)*
  71.                 sizeof(ntfs_attribute));
  72.  
  73.     ino->attr_count++;
  74.     ino->attrs[i].type=type;
  75.     ino->attrs[i].namelen=namelen;
  76.     ino->attrs[i].name=name;
  77.     *pos=i;
  78.     *found=0;
  79.     return 0;
  80. }
  81.  
  82. int 
  83. ntfs_make_attr_resident(ntfs_inode *ino,ntfs_attribute *attr)
  84. {
  85.     int size=attr->size;
  86.     if(size>0){
  87.         /* FIXME: read data, free clusters */
  88.         return EOPNOTSUPP;
  89.     }
  90.     attr->resident=1;
  91.     return 0;
  92. }
  93.  
  94. /* Store in the inode readable information about a run */
  95. void
  96. ntfs_insert_run(ntfs_attribute *attr,int cnum,ntfs_cluster_t cluster,int len)
  97. {
  98.     /* (re-)allocate space if necessary */
  99.     if(attr->d.r.len % 8 == 0) {
  100.         ntfs_runlist* new;
  101.         new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
  102.         if( !new )
  103.             return;
  104.         if( attr->d.r.runlist ) {
  105.             ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
  106.                     *sizeof(ntfs_runlist));
  107.             ntfs_free( attr->d.r.runlist );
  108.         }
  109.         attr->d.r.runlist = new;
  110.     }
  111.     if(attr->d.r.len>cnum)
  112.         ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum,
  113.                 (attr->d.r.len-cnum)*sizeof(ntfs_runlist));
  114.     attr->d.r.runlist[cnum].cluster=cluster;
  115.     attr->d.r.runlist[cnum].len=len;
  116.     attr->d.r.len++;
  117. }
  118.  
  119. /* Extends an attribute. Another run will be added if necessary,
  120.  * but we try to extend the last run in the runlist first.
  121.  * FIXME: what if there isn't enough contiguous space, we don't create
  122.  * multiple runs?
  123.  *
  124.  * *len: the desired new length of the attr (_not_ the amount to extend by)
  125.  */
  126. int ntfs_extend_attr(ntfs_inode *ino, ntfs_attribute *attr, int *len,
  127.         int flags)
  128. {
  129.     int error=0;
  130.     ntfs_runlist *rl;
  131.     int rlen;
  132.     ntfs_cluster_t cluster;
  133.     int clen;
  134.  
  135.     if(attr->compressed)return EOPNOTSUPP;
  136.     if(ino->record_count>1)return EOPNOTSUPP;
  137.  
  138.     if(attr->resident) {
  139.         error = ntfs_make_attr_nonresident(ino,attr);
  140.         if(error)
  141.             return error;
  142.     }
  143.  
  144.     if( *len <= attr->allocated )
  145.         return 0;       /* truely stupid things do sometimes happen */
  146.  
  147.     rl=attr->d.r.runlist;
  148.     rlen=attr->d.r.len-1;
  149.  
  150.     if(rlen>=0)
  151.         cluster=rl[rlen].cluster+rl[rlen].len;
  152.     else
  153.         /* no preference for allocation space */
  154.         cluster=0;
  155.  
  156.     /* calculate the extra space we need, and round up to multiple of cluster
  157.      * size to get number of new clusters needed */
  158.  
  159.     clen=( (*len - attr->allocated ) + ino->vol->clustersize - 1 ) /
  160.         ino->vol->clustersize;
  161.     if(clen==0)
  162.         return 0;
  163.  
  164.     /* FIXME: try to allocate smaller pieces */
  165.     error=ntfs_allocate_clusters(ino->vol,&cluster,&clen,
  166.                      flags|ALLOC_REQUIRE_SIZE);
  167.     if(error)return error;
  168.     attr->allocated += clen*ino->vol->clustersize;
  169.     *len = attr->allocated;
  170.  
  171.     /* contiguous chunk */
  172.     if(rlen>=0 && cluster==rl[rlen].cluster+rl[rlen].len){
  173.         rl[rlen].len += clen;
  174.         return 0;
  175.     }
  176.     ntfs_insert_run(attr,rlen+1,cluster,clen);
  177.     return 0;
  178. }
  179.  
  180. int
  181. ntfs_make_attr_nonresident(ntfs_inode *ino, ntfs_attribute *attr)
  182. {
  183.     void *data=attr->d.data;
  184.     int len=attr->size;
  185.     int error,alen;
  186.     ntfs_io io;
  187.     attr->d.r.len=0;
  188.     attr->d.r.runlist=0;
  189.     attr->resident=0;
  190.     attr->allocated=attr->initialized=0;
  191.     alen=len;
  192.     error=ntfs_extend_attr(ino,attr,&alen,ALLOC_REQUIRE_SIZE);
  193.     if(error)return error;/* FIXME: On error, restore old values */
  194.     io.fn_put=ntfs_put;
  195.     io.fn_get=ntfs_get;
  196.     io.param=data;
  197.     io.size=len;
  198.     io.do_read=0;
  199.     return ntfs_readwrite_attr(ino,attr,0,&io);
  200. }
  201.  
  202. int
  203. ntfs_attr_allnonresident(ntfs_inode *ino)
  204. {
  205.     int i, error=0;
  206.     ntfs_volume *vol = ino->vol;
  207.  
  208.     for (i=0; !error && i<ino->attr_count; i++)
  209.     {
  210.         if (ino->attrs[i].type != vol->at_security_descriptor
  211.             && ino->attrs[i].type != vol->at_data)
  212.             continue;
  213.         error = ntfs_make_attr_nonresident (ino, ino->attrs+i);
  214.     }
  215.     return error;
  216. }
  217.  
  218. /* Resize the attribute to a newsize */
  219. int ntfs_resize_attr(ntfs_inode *ino, ntfs_attribute *attr, int newsize)
  220. {
  221.     int error=0;
  222.     int oldsize=attr->size;
  223.     int clustersize=ino->vol->clustersize;
  224.     int i,count,newlen,newcount;
  225.     ntfs_runlist *rl;
  226.  
  227.     if(newsize==oldsize)
  228.         return 0;
  229.     /* modifying compressed attributes not supported yet */
  230.     if(attr->compressed)
  231.         /* extending is easy: just insert sparse runs */
  232.         return EOPNOTSUPP;
  233.     if(attr->resident){
  234.         void *v;
  235.         if(newsize>ino->vol->mft_recordsize){
  236.             error=ntfs_make_attr_nonresident(ino,attr);
  237.             if(error)return error;
  238.             return ntfs_resize_attr(ino,attr,newsize);
  239.         }
  240.         v=attr->d.data;
  241.         if(newsize){
  242.             attr->d.data=ntfs_malloc(newsize);
  243.             if(!attr->d.data) {
  244.                 ntfs_free(v);
  245.                 return ENOMEM;
  246.             }
  247.             if(newsize>oldsize)
  248.                 ntfs_bzero((char*)attr->d.data+oldsize,
  249.                        newsize-oldsize);
  250.             ntfs_memcpy((char*)attr->d.data,v,min(newsize,oldsize));
  251.         }else
  252.             attr->d.data=0;
  253.         ntfs_free(v);
  254.         attr->size=newsize;
  255.         return 0;
  256.     }
  257.     /* non-resident attribute */
  258.     rl=attr->d.r.runlist;
  259.     if(newsize<oldsize){
  260.         for(i=0,count=0;i<attr->d.r.len;i++){
  261.             if((count+rl[i].len)*clustersize>newsize)
  262.                 break;
  263.             count+=(int)rl[i].len;
  264.         }
  265.         newlen=i+1;
  266.         /* free unused clusters in current run, unless sparse */
  267.         newcount=count;
  268.         if(rl[i].cluster!=MAX_CLUSTER_T){
  269.             int rounded=newsize-count*clustersize;
  270.             rounded=(rounded+clustersize-1)/clustersize;
  271.             error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster+rounded,
  272.                                (int)rl[i].len-rounded);
  273.             if(error)
  274.                 return error; /* FIXME: incomplete operation */
  275.             rl[i].len=rounded;
  276.             newcount=count+rounded;
  277.         }
  278.         /* free all other runs */
  279.         for(i++;i<attr->d.r.len;i++)
  280.             if(rl[i].cluster!=MAX_CLUSTER_T){
  281.                 error=ntfs_deallocate_clusters(ino->vol,rl[i].cluster,(int)rl[i].len);
  282.                 if(error)
  283.                     return error; /* FIXME: incomplete operation */
  284.             }
  285.         /* FIXME? free space for extra runs in memory */
  286.         attr->d.r.len=newlen;
  287.     }else{
  288.         newlen=newsize;
  289.         error=ntfs_extend_attr(ino,attr,&newlen,ALLOC_REQUIRE_SIZE);
  290.         if(error)return error; /* FIXME: incomplete */
  291.         newcount=newlen/clustersize;
  292.     }
  293.     /* fill in new sizes */
  294.     attr->allocated = newcount*clustersize;
  295.     attr->size = newsize;
  296.     /* attr->initialized does not change. */
  297.     if(!newsize)
  298.         error=ntfs_make_attr_resident(ino,attr);
  299.     return error;
  300. }
  301.  
  302. int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
  303.     int dsize, ntfs_attribute **rattr)
  304. {
  305.     void *name;
  306.     int namelen;
  307.     int found,i;
  308.     int error;
  309.     ntfs_attribute *attr;
  310.     if(dsize>ino->vol->mft_recordsize)
  311.         /* FIXME: non-resident attributes */
  312.         return EOPNOTSUPP;
  313.     if(aname){
  314.         namelen=strlen(aname);
  315.         name=ntfs_malloc(2*namelen);
  316.         if( !name )
  317.             return ENOMEM;
  318.         ntfs_ascii2uni(name,aname,namelen);
  319.     }else{
  320.         name=0;
  321.         namelen=0;
  322.     }
  323.  
  324.     error = ntfs_new_attr(ino,anum,name,namelen,&i,&found,1);
  325.     if( error ) {
  326.         ntfs_free( name );
  327.         return error;
  328.     }
  329.  
  330.     if(found){
  331.         ntfs_free(name);
  332.         return EEXIST;
  333.     }
  334.     *rattr=attr=ino->attrs+i;
  335.     /* allocate a new number.
  336.        FIXME: Should this happen on inode writeback?
  337.        FIXME: extensions records not supported */
  338.     error=ntfs_allocate_attr_number(ino,&i);
  339.     if(error)
  340.         return error;
  341.     attr->attrno=i;
  342.  
  343.     attr->resident=1;
  344.     attr->compressed=attr->cengine=0;
  345.     attr->size=attr->allocated=attr->initialized=dsize;
  346.  
  347.     /* FIXME: INDEXED information should come from $AttrDef
  348.        Currently, only file names are indexed */
  349.     if(anum==ino->vol->at_file_name){
  350.         attr->indexed=1;
  351.     }else
  352.         attr->indexed=0;
  353.     attr->d.data=ntfs_malloc(dsize);
  354.  
  355.     if( !attr->d.data )
  356.         return ENOMEM;
  357.  
  358.     ntfs_memcpy(attr->d.data,data,dsize);
  359.     return 0;
  360. }
  361.  
  362. /* Non-resident attributes are stored in runs (intervals of clusters).
  363.  *
  364.  * This function stores in the inode readable information about a non-resident
  365.  * attribute.
  366.  */
  367. static int 
  368. ntfs_process_runs(ntfs_inode *ino,ntfs_attribute* attr,unsigned char *data)
  369. {
  370.     int startvcn,endvcn;
  371.     int vcn,cnum;
  372.     ntfs_cluster_t cluster;
  373.     int len,ctype;
  374.     startvcn = NTFS_GETU64(data+0x10);
  375.     endvcn = NTFS_GETU64(data+0x18);
  376.  
  377.     /* check whether this chunk really belongs to the end */
  378.     for(cnum=0,vcn=0;cnum<attr->d.r.len;cnum++)
  379.         vcn+=attr->d.r.runlist[cnum].len;
  380.     if(vcn!=startvcn)
  381.     {
  382.         ntfs_error("Problem with runlist in extended record\n");
  383.         return -1;
  384.     }
  385.     if(!endvcn)
  386.     {
  387.         endvcn = NTFS_GETU64(data+0x28)-1; /* allocated length */
  388.         endvcn /= ino->vol->clustersize;
  389.     }
  390.     data=data+NTFS_GETU16(data+0x20);
  391.     cnum=attr->d.r.len;
  392.     cluster=0;
  393.     for(vcn=startvcn; vcn<=endvcn; vcn+=len)
  394.     {
  395.         if(ntfs_decompress_run(&data,&len,&cluster,&ctype))
  396.             return -1;
  397.         if(ctype)
  398.             ntfs_insert_run(attr,cnum,-1,len);
  399.         else
  400.             ntfs_insert_run(attr,cnum,cluster,len);
  401.         cnum++;
  402.     }
  403.     return 0;
  404. }
  405.   
  406. /* Insert the attribute starting at attr in the inode ino */
  407. int ntfs_insert_attribute(ntfs_inode *ino, unsigned char* attrdata)
  408. {
  409.     int i,found;
  410.     int type;
  411.     short int *name;
  412.     int namelen;
  413.     void *data;
  414.     ntfs_attribute *attr;
  415.     int error;
  416.  
  417.     type = NTFS_GETU32(attrdata);
  418.     namelen = NTFS_GETU8(attrdata+9);
  419.     /* read the attribute's name if it has one */
  420.     if(!namelen)
  421.         name=0;
  422.     else
  423.     {
  424.         /* 1 Unicode character fits in 2 bytes */
  425.         name=ntfs_malloc(2*namelen);
  426.         if( !name )
  427.             return ENOMEM;
  428.  
  429.         ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen);
  430.     }
  431.  
  432.     error = ntfs_new_attr(ino,type,name,namelen,&i,&found,1);
  433.     if( error ) {
  434.         if( name ) ntfs_free( name );
  435.         return error;
  436.     }
  437.  
  438.     /* We can have in one inode two attributes with type 0x00000030 (File Name) 
  439.        and without name */
  440.     if(found && /*FIXME*/type!=ino->vol->at_file_name)
  441.     {
  442.         ntfs_process_runs(ino,ino->attrs+i,attrdata);
  443.         return 0;
  444.     } else if( found ) {
  445.         /*      Don't understand the above, but I know it leaks memory below
  446.             as it overwrites a found entry without freeing it. So here we
  447.             call ntfs_new_attr again but this time ask it to always allocate a
  448.             new     entry */
  449.         ntfs_new_attr(ino,type,name,namelen,&i,&found,0);
  450.     }
  451.     attr=ino->attrs+i;
  452.     attr->resident=NTFS_GETU8(attrdata+8)==0;
  453.     attr->compressed=NTFS_GETU16(attrdata+0xC);
  454.     attr->attrno=NTFS_GETU16(attrdata+0xE);
  455.   
  456.     if(attr->resident) {
  457.         attr->size=NTFS_GETU16(attrdata+0x10);
  458.         data=attrdata+NTFS_GETU16(attrdata+0x14);
  459.         attr->d.data = (void*)ntfs_malloc(attr->size);
  460.         if( !attr->d.data )
  461.             return ENOMEM;
  462.         ntfs_memcpy(attr->d.data,data,attr->size);
  463.         attr->indexed=NTFS_GETU16(attrdata+0x16);
  464.     }else{
  465.         attr->allocated=NTFS_GETU32(attrdata+0x28);
  466.         attr->size=NTFS_GETU32(attrdata+0x30);
  467.         attr->initialized=NTFS_GETU32(attrdata+0x38);
  468.         attr->cengine=NTFS_GETU16(attrdata+0x22);
  469.         if(attr->compressed)
  470.             attr->compsize=NTFS_GETU32(attrdata+0x40);
  471.         ino->attrs[i].d.r.runlist=0;
  472.         ino->attrs[i].d.r.len=0;
  473.         ntfs_process_runs(ino,attr,attrdata);
  474.     }
  475.     return 0;
  476. }
  477.  
  478. int
  479. ntfs_read_zero(ntfs_io *dest,int size)
  480. {
  481.     char *sparse=ntfs_calloc(512);
  482.     if(!sparse)
  483.         return ENOMEM;
  484.     while(size){
  485.         int i=min(size,512);
  486.         dest->fn_put(dest,sparse,i);
  487.         size-=i;
  488.     }
  489.     ntfs_free(sparse);
  490.     return 0;
  491. }
  492.  
  493. /* process compressed attributes */
  494. int ntfs_read_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
  495.     ntfs_io *dest)
  496. {
  497.     int error=0;
  498.     int clustersize,l;
  499.     int s_vcn,rnum,vcn,len,chunk,got,l1,offs1,copied;
  500.     ntfs_cluster_t cluster,cl1;
  501.     char *comp=0,*comp1;
  502.     char *decomp=0;
  503.     ntfs_io io;
  504.     ntfs_runlist *rl;
  505.  
  506.     l=dest->size;
  507.     clustersize=ino->vol->clustersize;
  508.     /* starting cluster of potential chunk
  509.        there are three situations:
  510.        a) in a large uncompressible or sparse chunk, 
  511.        s_vcn is in the middle of a run
  512.        b) s_vcn is right on a run border
  513.        c) when several runs make a chunk, s_vcn is before the chunks
  514.     */
  515.     s_vcn=offset/clustersize;
  516.     /* round down to multiple of 16 */
  517.     s_vcn &= ~15;
  518.     rl=attr->d.r.runlist;
  519.     for(rnum=vcn=0;rnum<attr->d.r.len && vcn+rl->len<=s_vcn;rnum++,rl++)
  520.         vcn+=rl->len;
  521.     if(rnum==attr->d.r.len){
  522.         /* beyond end of file */
  523.         /* FIXME: check allocated/initialized */
  524.         dest->size=0;
  525.         return 0;
  526.     }
  527.     io.do_read=1;
  528.     io.fn_put=ntfs_put;
  529.     io.fn_get=0;
  530.     cluster=rl->cluster;
  531.     len=rl->len;
  532.     copied=0;
  533.     while(l){
  534.         chunk=0;
  535.         if(cluster==MAX_CLUSTER_T){
  536.             /* sparse cluster */
  537.             int l1;
  538.             if((len-(s_vcn-vcn)) & 15)
  539.                 ntfs_error("unexpected sparse chunk size");
  540.             l1=chunk = min((vcn+len)*clustersize-offset,l);
  541.             error = ntfs_read_zero(dest,l1);
  542.             if(error)
  543.                 goto out;
  544.         }else if(dest->do_read){
  545.             if(!comp){
  546.                 comp=ntfs_malloc(16*clustersize);
  547.                 if(!comp){
  548.                     error=ENOMEM;
  549.                     goto out;
  550.                 }
  551.             }
  552.             got=0;
  553.             /* we might need to start in the middle of a run */
  554.             cl1=cluster+s_vcn-vcn;
  555.             comp1=comp;
  556.             do{
  557.                 io.param=comp1;
  558.                 l1=min(len-max(s_vcn-vcn,0),16-got);
  559.                 io.size=l1*clustersize;
  560.                 error=ntfs_getput_clusters(ino->vol,cl1,0,&io);
  561.                 if(error)goto out;
  562.                 if(l1+max(s_vcn-vcn,0)==len){
  563.                     rnum++;rl++;
  564.                     vcn+=len;
  565.                     cluster=cl1=rl->cluster;
  566.                     len=rl->len;
  567.                 }
  568.                 got+=l1;
  569.                 comp1+=l1*clustersize;
  570.             }while(cluster!=MAX_CLUSTER_T && got<16); /* until empty run */
  571.             chunk=16*clustersize;
  572.             if(cluster!=MAX_CLUSTER_T || got==16)
  573.                 /* uncompressible */
  574.                 comp1=comp;
  575.             else{
  576.                 if(!decomp){
  577.                     decomp=ntfs_malloc(16*clustersize);
  578.                     if(!decomp){
  579.                         error=ENOMEM;
  580.                         goto out;
  581.                     }
  582.                 }
  583.                 /* make sure there are null bytes
  584.                    after the last block */
  585.                 *(ntfs_u32*)comp1=0;
  586.                 ntfs_decompress(decomp,comp,chunk);
  587.                 comp1=decomp;
  588.             }
  589.             offs1=offset-s_vcn*clustersize;
  590.             chunk=min(16*clustersize-offs1,chunk);
  591.             chunk=min(l,chunk);
  592.             dest->fn_put(dest,comp1+offs1,chunk);
  593.         }
  594.         l-=chunk;
  595.         copied+=chunk;
  596.         offset+=chunk;
  597.         s_vcn=offset/clustersize & ~15;
  598.         if(l && offset>=((vcn+len)*clustersize)){
  599.             rnum++;rl++;
  600.             vcn+=len;
  601.             cluster=rl->cluster;
  602.             len=rl->len;
  603.         }
  604.     }
  605.  out:
  606.     if(comp)ntfs_free(comp);
  607.     if(decomp)ntfs_free(decomp);
  608.     dest->size=copied;
  609.     return error;
  610. }
  611.  
  612. int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, int offset,
  613.     ntfs_io *dest)
  614. {
  615.     return EOPNOTSUPP;
  616. }
  617.  
  618. /*
  619.  * Local variables:
  620.  * c-file-style: "linux"
  621.  * End:
  622.  */
  623.